1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.annotations.VisibleForTesting; 21 import com.google.common.base.Preconditions; 22 23 import java.util.Collection; 24 import java.util.HashMap; 25 import java.util.Set; 26 27 /** 28 * Implementation of {@link Multimap} using hash tables. 29 * 30 * <p>The multimap does not store duplicate key-value pairs. Adding a new 31 * key-value pair equal to an existing key-value pair has no effect. 32 * 33 * <p>Keys and values may be null. All optional multimap methods are supported, 34 * and all returned views are modifiable. 35 * 36 * <p>This class is not threadsafe when any concurrent operations update the 37 * multimap. Concurrent read operations will work correctly. To allow concurrent 38 * update operations, wrap your multimap with a call to {@link 39 * Multimaps#synchronizedSetMultimap}. 40 * 41 * @author Jared Levy 42 * @since 2.0 (imported from Google Collections Library) 43 */ 44 @GwtCompatible(serializable = true, emulated = true) 45 public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> { 46 private static final int DEFAULT_VALUES_PER_KEY = 2; 47 48 @VisibleForTesting 49 transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY; 50 51 /** 52 * Creates a new, empty {@code HashMultimap} with the default initial 53 * capacities. 54 */ 55 public static <K, V> HashMultimap<K, V> create() { 56 return new HashMultimap<K, V>(); 57 } 58 59 /** 60 * Constructs an empty {@code HashMultimap} with enough capacity to hold the 61 * specified numbers of keys and values without rehashing. 62 * 63 * @param expectedKeys the expected number of distinct keys 64 * @param expectedValuesPerKey the expected average number of values per key 65 * @throws IllegalArgumentException if {@code expectedKeys} or {@code 66 * expectedValuesPerKey} is negative 67 */ 68 public static <K, V> HashMultimap<K, V> create( 69 int expectedKeys, int expectedValuesPerKey) { 70 return new HashMultimap<K, V>(expectedKeys, expectedValuesPerKey); 71 } 72 73 /** 74 * Constructs a {@code HashMultimap} with the same mappings as the specified 75 * multimap. If a key-value mapping appears multiple times in the input 76 * multimap, it only appears once in the constructed multimap. 77 * 78 * @param multimap the multimap whose contents are copied to this multimap 79 */ 80 public static <K, V> HashMultimap<K, V> create( 81 Multimap<? extends K, ? extends V> multimap) { 82 return new HashMultimap<K, V>(multimap); 83 } 84 85 private HashMultimap() { 86 super(new HashMap<K, Collection<V>>()); 87 } 88 89 private HashMultimap(int expectedKeys, int expectedValuesPerKey) { 90 super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys)); 91 Preconditions.checkArgument(expectedValuesPerKey >= 0); 92 this.expectedValuesPerKey = expectedValuesPerKey; 93 } 94 95 private HashMultimap(Multimap<? extends K, ? extends V> multimap) { 96 super(Maps.<K, Collection<V>>newHashMapWithExpectedSize( 97 multimap.keySet().size())); 98 putAll(multimap); 99 } 100 101 /** 102 * {@inheritDoc} 103 * 104 * <p>Creates an empty {@code HashSet} for a collection of values for one key. 105 * 106 * @return a new {@code HashSet} containing a collection of values for one key 107 */ 108 @Override Set<V> createCollection() { 109 return Sets.<V>newHashSetWithExpectedSize(expectedValuesPerKey); 110 } 111 } 112